﻿using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using Kernelx.Contexts.Repositories; 
using System.Collections.Generic;
using System.Linq;


namespace Kernelx.Contexts.Configuration
{
    /// <summary>
    /// 
    /// </summary>
    public static class Repositories4EFCoreExtensions
    {
        #region RegisterModelibOfWork

        private static Dictionary<Type, Type> _dbContext2M = new Dictionary<Type, Type>();
        private static WorkloadContextOptions registerModelibOfWork(this WorkloadContextOptions ctxOpts)
        {
            if (_dbContext2M.Count == 0)
            {
                ctxOpts.Services.Add(new ServiceDescriptor(typeof(IModelibOfWork), p => {
                    var type = ServiceProviderExtensions.CurrentDbContext.Get();
                    var mt = type != null ? _dbContext2M[type] : _dbContext2M.FirstOrDefault().Value;
                    return p.GetService(mt) as IModelibOfWork;
                }, ServiceLifetime.Transient));
            }
            return ctxOpts;
        }

        /// <summary>
        ///注册<see cref="IModelibOfWork"/>的实例及依附的<see cref="DbContext"/>类型
        /// </summary>
        /// <typeparam name="TContext"></typeparam>
        /// <param name="ctxOpts"></param>
        /// <param name="optionsAction"></param>
        /// <param name="contextLifetime"></param>
        /// <param name="optionsLifetime"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterModelibOfWorkAndDbContext<TContext>(this WorkloadContextOptions ctxOpts, Action<DbContextOptionsBuilder> optionsAction = null,
        ServiceLifetime contextLifetime = ServiceLifetime.Scoped, ServiceLifetime optionsLifetime = ServiceLifetime.Scoped) where TContext : DbContext
        {
            var mt = typeof(ModelibOfWork<TContext>);
            ctxOpts.Services.Add(new ServiceDescriptor(mt, mt, contextLifetime));
            ctxOpts.Services.AddDbContext<TContext>(optionsAction, contextLifetime, optionsLifetime);

            _dbContext2M[typeof(TContext)] = mt;
            return ctxOpts.registerModelibOfWork();
        }

        /// <summary>
        /// 注册<see cref="IModelibOfWork"/>的实例及依附的<see cref="DbContext"/>类型
        /// </summary>
        /// <typeparam name="TContextService"></typeparam>
        /// <typeparam name="TContextImplementation"></typeparam>
        /// <param name="ctxOpts"></param>
        /// <param name="optionsAction"></param>
        /// <param name="contextLifetime"></param>
        /// <param name="optionsLifetime"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterModelibOfWorkAndDbContext<TContextService, TContextImplementation>(this WorkloadContextOptions ctxOpts,
            Action<DbContextOptionsBuilder> optionsAction = null, ServiceLifetime contextLifetime = ServiceLifetime.Scoped, ServiceLifetime optionsLifetime = ServiceLifetime.Scoped)
            where TContextImplementation : DbContext, TContextService
        {
            var mt = typeof(ModelibOfWork<TContextImplementation>);
            ctxOpts.Services.Add(new ServiceDescriptor(mt, p => new ModelibOfWork<TContextImplementation>(p.GetService<TContextService>() as TContextImplementation), contextLifetime));
            ctxOpts.Services.AddDbContext<TContextService, TContextImplementation>(optionsAction, contextLifetime, optionsLifetime);

            _dbContext2M[typeof(TContextImplementation)] = mt;
            return ctxOpts.registerModelibOfWork();
        }


        /// <summary>
        /// 注册<see cref="IModelibOfWork"/>的实例及依附的<see cref="DbContext"/>类型
        /// </summary>
        /// <typeparam name="TContext"></typeparam>
        /// <param name="ctxOpts"></param>
        /// <param name="optionsAction"></param>
        /// <param name="contextLifetime"></param>
        /// <param name="optionsLifetime"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterModelibOfWorkAndDbContext<TContext>(this WorkloadContextOptions ctxOpts, Action<IServiceProvider, DbContextOptionsBuilder> optionsAction,
            ServiceLifetime contextLifetime = ServiceLifetime.Scoped, ServiceLifetime optionsLifetime = ServiceLifetime.Scoped)
            where TContext : DbContext
        {
            var mt = typeof(ModelibOfWork<TContext>);
            ctxOpts.Services.Add(new ServiceDescriptor(mt, mt, contextLifetime));
            ctxOpts.Services.AddDbContext<TContext>(optionsAction, contextLifetime, optionsLifetime);

            _dbContext2M[typeof(TContext)] = mt;
            return ctxOpts.registerModelibOfWork();
        }


        /// <summary>
        /// 注册<see cref="IModelibOfWork"/>的实例及依附的<see cref="DbContext"/>类型
        /// </summary>
        /// <typeparam name="TContextService"></typeparam>
        /// <typeparam name="TContextImplementation"></typeparam>
        /// <param name="ctxOpts"></param>
        /// <param name="optionsAction"></param>
        /// <param name="contextLifetime"></param>
        /// <param name="optionsLifetime"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterModelibOfWorkAndDbContext<TContextService, TContextImplementation>(this WorkloadContextOptions ctxOpts, Action<IServiceProvider,
            DbContextOptionsBuilder> optionsAction, ServiceLifetime contextLifetime = ServiceLifetime.Scoped, ServiceLifetime optionsLifetime = ServiceLifetime.Scoped) where TContextImplementation : DbContext, TContextService
        {
            var mt = typeof(ModelibOfWork<TContextImplementation>);
            ctxOpts.Services.Add(new ServiceDescriptor(mt, p => new ModelibOfWork<TContextImplementation>(p.GetService<TContextService>() as TContextImplementation), contextLifetime));
            ctxOpts.Services.AddDbContext<TContextService, TContextImplementation>(optionsAction, contextLifetime, optionsLifetime);

            _dbContext2M[typeof(TContextImplementation)] = mt;
            return ctxOpts.registerModelibOfWork();
        }


        /// <summary>
        /// 注册<see cref="IModelibOfWork"/>的实例及依附的<see cref="DbContext"/>类型
        /// </summary>
        /// <typeparam name="TContext"></typeparam>
        /// <param name="ctxOpts"></param>
        /// <param name="optionsAction"></param>
        /// <param name="poolSize"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterModelibOfWorkAndDbContextPool<TContext>(this WorkloadContextOptions ctxOpts, Action<DbContextOptionsBuilder> optionsAction, int poolSize = 128)
            where TContext : DbContext
        {
            var mt = typeof(ModelibOfWork<TContext>);
            ctxOpts.Services.Add(new ServiceDescriptor(mt, mt, ServiceLifetime.Transient));
            ctxOpts.Services.AddDbContextPool<TContext>(optionsAction, poolSize);

            _dbContext2M[typeof(TContext)] = mt;
            return ctxOpts.registerModelibOfWork();
        }

        /// <summary>
        /// 注册<see cref="IModelibOfWork"/>的实例及依附的<see cref="DbContext"/>类型
        /// </summary>
        /// <typeparam name="TContextService"></typeparam>
        /// <typeparam name="TContextImplementation"></typeparam>
        /// <param name="ctxOpts"></param>
        /// <param name="optionsAction"></param>
        /// <param name="poolSize"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterModelibOfWorkAndDbContextPool<TContextService, TContextImplementation>(this WorkloadContextOptions ctxOpts
            , Action<DbContextOptionsBuilder> optionsAction, int poolSize = 128)
            where TContextService : class
            where TContextImplementation : DbContext, TContextService
        {
            var mt = typeof(ModelibOfWork<TContextImplementation>);
            ctxOpts.Services.Add(new ServiceDescriptor(mt,
              p => new ModelibOfWork<TContextImplementation>(p.GetService<TContextService>() as TContextImplementation), ServiceLifetime.Transient));
            ctxOpts.Services.AddDbContextPool<TContextService, TContextImplementation>(optionsAction, poolSize);

            _dbContext2M[typeof(TContextImplementation)] = mt;
            return ctxOpts.registerModelibOfWork();
        }

        /// <summary>
        /// 注册<see cref="IModelibOfWork"/>的实例及依附的<see cref="DbContext"/>类型
        /// </summary>
        /// <typeparam name="TContext"></typeparam>
        /// <param name="ctxOpts"></param>
        /// <param name="optionsAction"></param>
        /// <param name="poolSize"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterModelibOfWorkAndDbContextPool<TContext>(this WorkloadContextOptions ctxOpts
            , Action<IServiceProvider, DbContextOptionsBuilder> optionsAction, int poolSize = 128)
            where TContext : DbContext
        {
            var mt = typeof(ModelibOfWork<TContext>);
            ctxOpts.Services.Add(new ServiceDescriptor(mt, mt, ServiceLifetime.Transient));
            ctxOpts.Services.AddDbContextPool<TContext>(optionsAction, poolSize);

            _dbContext2M[typeof(TContext)] = mt;
            return ctxOpts.registerModelibOfWork();
        }

        /// <summary>
        /// 注册<see cref="IModelibOfWork"/>的实例及依附的<see cref="DbContext"/>类型
        /// </summary>
        /// <typeparam name="TContextService"></typeparam>
        /// <typeparam name="TContextImplementation"></typeparam>
        /// <param name="ctxOpts"></param>
        /// <param name="optionsAction"></param>
        /// <param name="poolSize"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterModelibOfWorkAndDbContextPool<TContextService, TContextImplementation>(this WorkloadContextOptions ctxOpts
            , Action<IServiceProvider, DbContextOptionsBuilder> optionsAction, int poolSize = 128)
            where TContextService : class
            where TContextImplementation : DbContext, TContextService
        {
            var mt = typeof(ModelibOfWork<TContextImplementation>);
            ctxOpts.Services.Add(new ServiceDescriptor(mt, p => new ModelibOfWork<TContextImplementation>(p.GetService<TContextService>() as TContextImplementation), ServiceLifetime.Transient));
            ctxOpts.Services.AddDbContextPool<TContextService, TContextImplementation>(optionsAction, poolSize);

            _dbContext2M[typeof(TContextImplementation)] = mt;
            return ctxOpts.registerModelibOfWork();
        }


        /// <summary>
        /// 注册<see cref="IModelibOfWork"/>的实例及依附的<see cref="DbContext"/>类型
        /// </summary>
        /// <typeparam name="TContext"></typeparam>
        /// <param name="ctxOpts"></param>
        /// <param name="optionsAction"></param>
        /// <param name="lifetime"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterModelibOfWorkAndDbContextFactory<TContext>(this WorkloadContextOptions ctxOpts
            , Action<DbContextOptionsBuilder> optionsAction = null, ServiceLifetime lifetime = ServiceLifetime.Singleton)
            where TContext : DbContext
        {
            var mt = typeof(ModelibOfWork<TContext>);
            ctxOpts.Services.Add(new ServiceDescriptor(mt, mt, lifetime));
            ctxOpts.Services.AddDbContextFactory<TContext>(optionsAction, lifetime);

            _dbContext2M[typeof(TContext)] = mt;
            return ctxOpts.registerModelibOfWork();
        }


        /// <summary>
        /// 注册<see cref="IModelibOfWork"/>的实例及依附的<see cref="DbContext"/>类型
        /// </summary>
        /// <typeparam name="TContext"></typeparam>
        /// <typeparam name="TFactory"></typeparam>
        /// <param name="ctxOpts"></param>
        /// <param name="optionsAction"></param>
        /// <param name="lifetime"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterModelibOfWorkAndDbContextFactory<TContext, TFactory>(this WorkloadContextOptions ctxOpts
            , Action<DbContextOptionsBuilder> optionsAction = null, ServiceLifetime lifetime = ServiceLifetime.Singleton)
            where TContext : DbContext
            where TFactory : IDbContextFactory<TContext>
        {
            var mt = typeof(ModelibOfWork<TContext>);
            ctxOpts.Services.Add(new ServiceDescriptor(mt, mt, lifetime));
            ctxOpts.Services.AddDbContextFactory<TContext, TFactory>(optionsAction, lifetime);

            _dbContext2M[typeof(TContext)] = mt;
            return ctxOpts.registerModelibOfWork();
        }

        /// <summary>
        /// 注册<see cref="IModelibOfWork"/>的实例及依附的<see cref="DbContext"/>类型
        /// </summary>
        /// <typeparam name="TContext"></typeparam>
        /// <param name="ctxOpts"></param>
        /// <param name="optionsAction"></param>
        /// <param name="lifetime"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterModelibOfWorkAndDbContextFactory<TContext>(this WorkloadContextOptions ctxOpts, Action<IServiceProvider, DbContextOptionsBuilder> optionsAction,
            ServiceLifetime lifetime = ServiceLifetime.Singleton) where TContext : DbContext
        {
            var mt = typeof(ModelibOfWork<TContext>);
            ctxOpts.Services.Add(new ServiceDescriptor(mt, mt, lifetime));
            ctxOpts.Services.AddDbContextFactory<TContext>(optionsAction, lifetime);

            _dbContext2M[typeof(TContext)] = mt;
            return ctxOpts.registerModelibOfWork();
        }

        /// <summary>
        /// 注册<see cref="IModelibOfWork"/>的实例及依附的<see cref="DbContext"/>类型
        /// </summary>
        /// <typeparam name="TContext"></typeparam>
        /// <typeparam name="TFactory"></typeparam>
        /// <param name="ctxOpts"></param>
        /// <param name="optionsAction"></param>
        /// <param name="lifetime"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterModelibOfWorkAndDbContextFactory<TContext, TFactory>(this WorkloadContextOptions ctxOpts
            , Action<IServiceProvider, DbContextOptionsBuilder> optionsAction,
            ServiceLifetime lifetime = ServiceLifetime.Singleton) where TContext : DbContext where TFactory : IDbContextFactory<TContext>
        {
            var mt = typeof(ModelibOfWork<TContext>);
            ctxOpts.Services.Add(new ServiceDescriptor(mt, mt, lifetime));
            ctxOpts.Services.AddDbContextFactory<TContext, TFactory>(optionsAction, lifetime);

            _dbContext2M[typeof(TContext)] = mt;
            return ctxOpts.registerModelibOfWork();
        }

        /// <summary>
        /// 注册<see cref="IModelibOfWork"/>的实例及依附的<see cref="DbContext"/>类型
        /// </summary>
        /// <typeparam name="TContext"></typeparam>
        /// <param name="ctxOpts"></param>
        /// <param name="optionsAction"></param>
        /// <param name="poolSize"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterModelibOfWorkAndDbContextFactory<TContext>(this WorkloadContextOptions ctxOpts
            , Action<DbContextOptionsBuilder> optionsAction, int poolSize = 128)
            where TContext : DbContext
        {
            var mt = typeof(ModelibOfWork<TContext>);
            ctxOpts.Services.Add(new ServiceDescriptor(mt, mt, ServiceLifetime.Transient));
            ctxOpts.Services.AddPooledDbContextFactory<TContext>(optionsAction, poolSize);

            _dbContext2M[typeof(TContext)] = mt;
            return ctxOpts.registerModelibOfWork();
        }

        /// <summary>
        /// 注册<see cref="IModelibOfWork"/>的实例及依附的<see cref="DbContext"/>类型
        /// </summary>
        /// <typeparam name="TContext"></typeparam>
        /// <param name="ctxOpts"></param>
        /// <param name="optionsAction"></param>
        /// <param name="poolSize"></param>
        /// <returns></returns>
        public static WorkloadContextOptions RegisterModelibOfWorkAndDbContextFactory<TContext>(this WorkloadContextOptions ctxOpts
            , Action<IServiceProvider, DbContextOptionsBuilder> optionsAction, int poolSize = 128)
            where TContext : DbContext
        {
            var mt = typeof(ModelibOfWork<TContext>);
            ctxOpts.Services.Add(new ServiceDescriptor(mt, mt, ServiceLifetime.Transient));
            ctxOpts.Services.AddPooledDbContextFactory<TContext>(optionsAction, poolSize);

            _dbContext2M[typeof(TContext)] = mt;
            return ctxOpts.registerModelibOfWork();
        }

        #endregion 
    } 
}
